package com.novix.struts.action;

import java.util.Enumeration;
import java.util.Vector;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

import lotus.domino.Document;
import lotus.domino.NotesException;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.log4j.Logger;
import org.apache.struts.action.Action;

import com.automatedlogic.domino.sso.DominoBridge;
import com.automatedlogic.domino.sso.DominoDirectoryConstants;
import com.automatedlogic.domino.sso.LtpaToken;
import com.novix.portal.framework.exceptions.ApplicationException;
import com.novix.portal.framework.exceptions.CaptiveNotFoundException;
import com.novix.portal.framework.exceptions.TokenMissingException;
import com.novix.portal.framework.exceptions.UserMissingException;
import com.novix.portal.framework.model.IPortalUser;
import com.novix.portal.framework.service.IGenericService;
import com.novix.portal.framework.service.IGenericServiceFactory;
import com.novix.portal.framework.util.IConstants;
import com.novix.portal.framework.util.UserContainer;
import com.novix.utility.web.Messages;

abstract public class PortalBaseAction extends Action {
    /**
     * Logger for this class
     */
    private static final Logger logger = Logger.getLogger(PortalBaseAction.class);

    Log log = LogFactory.getLog(this.getClass());

    protected IGenericService getPortalService() {
        IGenericServiceFactory factory = (IGenericServiceFactory) getApplicationObject(IConstants.SERVICE_FACTORY_KEY);
        IGenericService service = null;
        try {
            service = factory.createService();
        } catch (Exception ex) {
            log.error("Problem creating the Service Layer", ex);
            throw new ApplicationException("Problem creating the Service Layer", ex);
        }
        return service;
    }

    /**
     * Retrieve a session object based on the request and the attribute name.
     */
    protected Object getSessionObject(HttpServletRequest req, String attrName) {
        Object sessionObj = null;
        HttpSession session = req.getSession(false);
        if (session != null) {
            sessionObj = session.getAttribute(attrName);
        }
        return sessionObj;
    }

    /**
     * Retrieve the UserContainer for the user tier to the request.
     */
    protected UserContainer getUserContainer(HttpServletRequest request) {

        UserContainer userContainer = (UserContainer) getSessionObject(request, IConstants.USER_CONTAINER);

        // Create a UserContainer for the user if it doesn't exist already
        if (userContainer == null) {
            userContainer = new UserContainer();
            HttpSession session = request.getSession(true);
            session.setAttribute(IConstants.USER_CONTAINER, userContainer);
        }

        return userContainer;
    }

    /**
     * Retrieve an object from the application scope by its name. This is a
     * convience method.
     */
    protected Object getApplicationObject(String attrName) {
        return servlet.getServletContext().getAttribute(attrName);
    }

    protected String getApplicationParam(String paramName) {
        return servlet.getServletContext().getInitParameter(paramName);
    }

    /**
     * @param request
     * @param uc
     * @param captive
     * @param pu
     */
    protected void setUserToken(HttpServletRequest request, UserContainer uc) {
        LtpaToken ltpaToken = new LtpaToken(request);
        String token = ltpaToken.getTokenString();
        if (token == null)
            throw new TokenMissingException();
        if (uc == null)
            uc = getUserContainer(request);
        IPortalUser pu = uc.getUser();
        if (pu == null)
            throw new UserMissingException();
        pu.setToken(token);
        uc.setToken(token);
    }

    public String checkDominoUserProfile(HttpServletRequest req, String dominoServer) {

        //Open a session with the Domino server. The Domino server must be
        // running the HTTP and DIIOP tasks, and must accept connections for the
        // user.
        DominoBridge dominoBridge = new DominoBridge();
        String userName;
        try {
            userName = getUserName(req, dominoServer, dominoBridge);
        } catch (NotesException e1) {
            throw new CaptiveNotFoundException(e1);
        }
        dominoBridge.openDominoSession(dominoServer, Messages.getString("CacheLoader.name"), Messages.getString("CacheLoader.password"));
        //dominoBridge.openDominoSession(req, dominoServer);
        String captive = null;
        //Collect information about the user, if a session was opened with the
        // Domino server.
        if (dominoBridge.isDominoSessionAvailable()) {

            //Get the current user's Person Document in the Domino Directory.
            // The user must have access to Read their own Person document from
            // the directory.
            Document doc = getPersonDocument(dominoBridge, userName);
            try {
                captive = doc.getItemValueString(IConstants.NOTES_DOCUMENT_CAPTIVE_FIELD_NAME);
                if (logger.isDebugEnabled()) {
                    logger.debug("person doc's UNID is " + doc.getUniversalID());
                    logger.debug("user's full name is " + doc.getItemValueString("FullName"));
                }
            } catch (NotesException e) {
                logger.error(e);
            } finally {
                //Close the session with the Domino server.
                dominoBridge.closeDominoSession();
            }
        }
        return captive;
    }

    /**
     * @param req
     * @param dominoServer
     * @param dominoBridge
     * @return
     * @throws NotesException
     */
    private String getUserName(HttpServletRequest req, String dominoServer, DominoBridge dominoBridge) throws NotesException {
        String userName = null;
        dominoBridge.openDominoSession(req, dominoServer);
        userName = dominoBridge.dominoSession.getUserName();
        dominoBridge.closeDominoSession();
        return userName;
    }

    /**
     * Open the Domino server's Directory Assistance listing, look at each
     * Domino Directory, and find the user's Person document.
     * 
     * @param dominoBridge
     *            An active session must be available to the Domino server.
     * @return Document from a Domino Directory database.
     */
    lotus.domino.Document getPersonDocument(DominoBridge dominoBridge, String userName) {

        try {

            //Look at each directory until we find the user's Person document.
            lotus.domino.Database dominoDirectoryDatabase;
            Vector books = dominoBridge.dominoSession.getAddressBooks();
            Enumeration b = books.elements();

            while (b.hasMoreElements()) {
                dominoDirectoryDatabase = (lotus.domino.Database) b.nextElement();

                try {
                    //The database can be opened if the user has access to it.
                    if (dominoDirectoryDatabase.open()) {

                        //Open a view in the Domino database.
                        lotus.domino.View dominoDirectoryView = dominoDirectoryDatabase.getView(DominoDirectoryConstants.dominoDirectoryViewName);
                        if (dominoDirectoryView != null) {
                            //Find the Person document.
                            lotus.domino.Document personDocument = dominoDirectoryView.getDocumentByKey(userName, true);
                            //Ignore any Person document that has been deleted.
                            if (personDocument != null) {
                                if (personDocument.isValid()) {
                                    if (!personDocument.isDeleted()) {
                                        return personDocument;
                                    }
                                }
                            }
                        }

                    }

                } catch (NotesException e) {
                    logger.error(e);
                }

            }
        } catch (NotesException e) {
            logger.error(e);
        } catch (Exception e) {
            logger.error(e);
        }
        return null;
    }
}
